﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using Sherwood.Configuration;
using System.IO;
using System.Xml;
using Sherwood.SignOn.Server.Models.Services;
using Sherwood.SignOn.Server.Models.Configuration;

namespace Sherwood.SignOn.Server.Models.Repositories.Config
{
    public class ConfigUserProfileRepository : Sherwood.SignOn.Server.Models.Repositories.IUserProfileRepository
    {

        public ConfigUserProfileRepository()
        {

        }

        private List<IProfileProvider> _providers = null;

        /// <summary>
        /// Returns profile providers loaded from a config file.
        /// </summary>
        public IEnumerable<IProfileProvider> ProfileProviders
        {
            get
            {
                if (_providers == null)
                {
                    _providers = new List<IProfileProvider>();
                    foreach (RoleProvidersElement roleProvider in SignOnServerSection.Instance.RoleProviders)
                    {
                        var type = Type.GetType(roleProvider.Type, true);
                        var instance = DependencyInjection.Container.Resolve(type, null);
                        if (instance is IProfileProvider)
                        {
                            if (instance is IXmlConfigurable)
                            {
                                StringReader sr = new StringReader(roleProvider.InnerXml);
                                XmlReader reader = new XmlTextReader(sr);
                                ((IXmlConfigurable)instance).Configure(reader);
                                reader.Close();
                                sr.Close();
                            }
                            _providers.Add((IProfileProvider)instance);
                        }
                    }
                }
                return _providers;
            }
        }

        /// <summary>
        /// Returns the basic profile XML for the user associated with the userAccount.
        /// </summary>
        /// <param name="account">User account to get profile for</param>
        /// <param name="requestClientCode">Code of the requesting client</param>
        /// <returns>Basic UserProfile XML (without extra roles or attributes)</returns>
        public string GetBasicProfileXml(IUserAccount account, string requestClientCode)
        {
            if (account != null)
            {
                //Build profile XML
                var profile = new getUserProfileResponse();
                profile.username = account.UserName;
                profile.lastName = account.LastName;
                profile.firstName = account.FirstName;
                profile.gender = (int) account.Gender;
                profile.globalUser = UserAccountHelper.IsGlobalAccount(account.UserName);
                profile.dateOfBirth = account.DateOfBirth.GetValueOrDefault();
                profile.email = account.Email;
                profile.country = account.Country;
                profile.culture = new List<culture> { new culture { name = account.CultureName1, priority = 0 }, new culture { name = account.CultureName2, priority = 1 }, new culture { name = account.CultureName3, priority = 2 } };
                profile.userAccountId = account.Id.ToString();

                string xml = profile.ToString();
                return xml;
            }
            return "";
        }

        /// <summary>
        /// Returns the full profile XML for the user linked to the specifeid session by aggregating
        /// roles/attributes from different role providers.
        /// </summary>
        /// <param name="session">IUserSession object</param>
        /// <param name="requestClientCode">Code of client requesting roles (this may be used by role providers to help determine which roles to return).</param>
        /// <returns>UserProfile XML (with roles /attributes) for user associated with session</returns>
        public string GetSessionProfileXml(IUserSession session, string requestClientCode)
        {
            string cacheKey = "SSOProfileXML"+session.Id;
            string profileXml = GetCacheValue(cacheKey)  as string;
            if (profileXml != null)
            {
                return profileXml;
            }
            else
            {
                if (session != null && session.UserAccount != null)
                {
                    //Retrieve all roles for user/session
                    var allRoles = new List<RoleInfo>();
                    var allAttributes = new List<AttributeInfo>();

                    foreach (var provider in ProfileProviders)
                    {
                        RoleInfo[] roles = null;
                        AttributeInfo[] attributes = null;
                        provider.GetRoles(session, requestClientCode, out roles, out attributes);
                        if (roles != null)
                        {
                            allRoles.AddRange(roles);
                        }
                        if (attributes != null)
                        {
                            allAttributes.AddRange(attributes);
                        }
                    }


                    //Build profile XML
                    IUserAccount account = session.UserAccount;
                    var profile = new getUserProfileResponse();
                    profile.username = account.UserName;
                    profile.lastName = account.LastName;
                    profile.firstName = account.FirstName;
                    profile.globalUser = UserAccountHelper.IsGlobalAccount(account.UserName);
                    profile.gender = (int)account.Gender;
                    profile.dateOfBirth = account.DateOfBirth.GetValueOrDefault();
                    profile.email = account.Email;
                    profile.country = account.Country;
                    profile.culture = new List<culture> { new culture { name = account.CultureName1, priority = 0 }, new culture { name = account.CultureName2, priority = 1 }, new culture { name = account.CultureName3, priority = 2 } };
                    profile.userAccountId = account.Id.ToString();
                    profile.role = new List<role>();
                    foreach (RoleInfo roleInf in allRoles)
                    {
                        var rl = new role {name = roleInf.Name, source = roleInf.Source};
                        profile.role.Add(rl);
                    }
                    profile.attribute = new List<attribute>();
                    foreach (AttributeInfo attributeInf in allAttributes)
                    {
                        var attr = new attribute
                                             {
                                                 name = attributeInf.Name,
                                                 source = attributeInf.Source,
                                                 value = attributeInf.Value
                                             };
                        profile.attribute.Add(attr);
                    }

                    string xml = profile.ToString();
                    SetCacheValue(cacheKey,xml);
                    return xml;
                }
            }
            return "";
        }

        private Dictionary<string, object> _dummyCache;
        protected object GetCacheValue(string key)
        {
            if (HttpContext.Current != null)
            {
                return HttpContext.Current.Cache[key];
            }
            else
            {
                if (_dummyCache != null && _dummyCache.ContainsKey(key))
                {
                    return _dummyCache[key];
                }
            }
            return null;

        }

        protected void SetCacheValue(string key, object value)
        {
            if (HttpContext.Current != null)
            {
                HttpContext.Current.Cache.Add(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 5, 0), System.Web.Caching.CacheItemPriority.Normal, null);
            }
            else
            {
                if (_dummyCache == null)
                    _dummyCache = new Dictionary<string, object>();
                _dummyCache[key] = value;
            }
        }

    }
}